/**
 * 
 */
package com.uit.project.bustrip.database;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

import com.uit.project.bustrip.appconfig.AppsConfig;
import com.uit.project.bustrip.entity.BaseEntity;
import com.uit.project.bustrip.factory.EntityFactory;
import com.uit.project.bustrip.valueobject.QueryOption;

/**
 * @author Nguyen
 *
 */
public class DBHelper extends SQLiteOpenHelper {

	public static final String TAG = "DBHelper";
	public static final String CREATE = "Create";
	public static final String INSERT = "Insert";
	public static final String UPDATE = "Update";
	public static final String DELETE = "Delete";
	public static final String GETALL = "GetAll";
	public static final String EXECUTE = "Execute";
	public static DBHelper instance = null;
	
	public DBHelper(Context context) {
		super(context, AppsConfig.DB_NAME, null, AppsConfig.DB_VERSION);
	}

	public static synchronized DBHelper getInstance(Context context) {
		if(instance == null)
			return new DBHelper(context);
		return instance;
	}

	/* (non-Javadoc)
	 * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase)
	 */
	@Override
	public void onCreate(SQLiteDatabase db) {
		for (Class<?> clazz : AppsConfig.entityList()) {
			BaseEntity entity =  (BaseEntity) EntityFactory.instance(clazz);
			createTable(db, entity);
		}
	}
	private void createTable(SQLiteDatabase db,BaseEntity entity){
		String sql = entity.createTableString();
		db.execSQL(sql);
	}	
	private void destroyTable(SQLiteDatabase db, String table){
		db.execSQL("DROP TABLE IF EXISTS " + table);
		onCreate(db);
		Log.i("DBHelper Destroy", "Destroy table " + table);
	}
	/* (non-Javadoc)
	 * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
	 */
	@Override
	public void onUpgrade(SQLiteDatabase db, int arg1, int arg2) {
		for (Class<?> clazz : AppsConfig.entityList()) {
			destroyTable(db,clazz.getSimpleName());
		}
	}
	/**
	 * Convenience method for deleting rows in the database.
	 * @param table
	 * @param whereClause
	 * @param whereArgs
	 * @return the number of rows affected if a whereClause is passed in, 0 otherwise. To remove all rows and get a count pass "1" as the whereClause.
	 */
	public int delete(String table, String whereClause, String[] whereArgs){
		SQLiteDatabase mdb = getWritableDatabase();
		Log.i(TAG + " - " + DELETE, table);
		return mdb.delete(table, whereClause, whereArgs);
	}
	/**
	 * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
	 * @param sql
	 */
	public void execSQL(String sql){
		SQLiteDatabase mdb = getWritableDatabase();
		Log.i(TAG + " - " + EXECUTE, sql);
		mdb.execSQL(sql);
	}
	/**
	 * Execute a single SQL statement that is NOT a SELECT/INSERT/UPDATE/DELETE.
	 * @param sql
	 * @param bindArgs
	 */
	public void execSQL(String sql,Object[] bindArgs){
		SQLiteDatabase mdb = getWritableDatabase();
		Log.i(TAG + " - " + EXECUTE, sql);
		mdb.execSQL(sql,bindArgs);
	}
	/**
	 * 
	 * @param table the table to insert the row into.
	 * @param nullColumnHack
	 * @param values this map contains the initial column values for the row. The keys should be the column names and the values the column values.
	 * @return the row ID of the newly inserted row, or -1 if an error occurred.
	 */
	public long insert (String table, String nullColumnHack, ContentValues values){
		SQLiteDatabase mdb = getWritableDatabase();
		Log.i(TAG + " - " + INSERT, table);
		return mdb.insert(table, nullColumnHack, values);
	}
	/**
	 * <a href="http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html#query(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, java.lang.String, java.lang.String, java.lang.String)">see at Android Developer</a>
	 * @param table The table name to compile the query against.
	 * @param columns
	 * @param selection
	 * @param selectionArgs
	 * @param groupBy
	 * @param having
	 * @param orderBy
	 * @param limit
	 * @return Query the given URL, returning a Cursor over the result set.
	 */
	public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit){
		SQLiteDatabase mdb = getWritableDatabase();
		Log.i(TAG + " - " + GETALL, table);
		return mdb.query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit);
	}
	/**
	 * Query table with QueryOption.
	 * @param q
	 * @return Query the given URL, returning a Cursor over the result set.
	 */
	public Cursor query(QueryOption q){
		SQLiteDatabase mdb = getWritableDatabase();
		Log.i(TAG + " - " + GETALL, q.getTable());
		return mdb.query(q.getTable(), q.getColumns(), q.getSelection(), q.getSelectionArgs(), q.getGroupBy(), q.getHaving(), q.getOrderBy(), q.getLimit());
	}
	/**
	 * Convenience method for updating rows in the database.
	 * @param table the table to update in.
	 * @param values a map from column names to new column values. null is a valid value that will be translated to NULL.
	 * @param whereClause the optional WHERE clause to apply when updating. Passing null will update all rows.
	 * @param whereArgs
	 * @return the number of rows affected.
	 */
	public int update (String table, ContentValues values, String whereClause, String[] whereArgs){
		SQLiteDatabase mdb = getWritableDatabase();
		Log.i(TAG + " - " + UPDATE, table);
		return mdb.update(table, values, whereClause, whereArgs);
	}
}
